package org.codehaus.activemq.message;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.UTFDataFormatException;
import javax.jms.JMSException;
import javax.jms.MessageNotWriteableException;
import javax.jms.TextMessage;

public class ActiveMQTextMessage extends ActiveMQMessage
  implements TextMessage
{
  private String text;

  public String toString()
  {
    String payload = null;
    try {
      payload = getText();
    }
    catch (JMSException e) {
      payload = "could not read payload: " + e.toString();
    }
    return super.toString() + ", text = " + payload;
  }

  public int getPacketType()
  {
    return 7;
  }

  public ActiveMQMessage shallowCopy()
    throws JMSException
  {
    ActiveMQTextMessage other = new ActiveMQTextMessage();
    initializeOther(other);
    other.text = this.text;
    return other;
  }

  public ActiveMQMessage deepCopy()
    throws JMSException
  {
    return shallowCopy();
  }

  public void clearBody()
    throws JMSException
  {
    super.clearBody();
    this.text = null;
  }

  public void setText(String string)
    throws JMSException
  {
    if (this.readOnlyMessage) {
      throw new MessageNotWriteableException("The message is read only");
    }
    this.text = string;
  }

  void setTextPayload(String string) {
    this.text = string;
  }

  public String getText()
    throws JMSException
  {
    if (this.text == null) {
      try {
        super.buildBodyFromBytes();
      }
      catch (IOException ioe) {
        JMSException jmsEx = new JMSException("failed to build body from bytes");
        jmsEx.setLinkedException(ioe);
        throw jmsEx;
      }
    }
    return this.text;
  }

  protected void writeBody(DataOutput dataOut)
    throws IOException
  {
    if (this.text != null) {
      int strlen = this.text.length();
      int utflen = 0;
      char[] charr = new char[strlen];
      int count = 0;

      this.text.getChars(0, strlen, charr, 0);

      for (int i = 0; i < strlen; i++) {
        int c = charr[i];
        if ((c >= 1) && (c <= 127)) {
          utflen++;
        }
        else if (c > 2047) {
          utflen += 3;
        }
        else {
          utflen += 2;
        }
      }

      byte[] bytearr = new byte[utflen + 4];
      bytearr[(count++)] = (byte)(utflen >>> 24 & 0xFF);
      bytearr[(count++)] = (byte)(utflen >>> 16 & 0xFF);
      bytearr[(count++)] = (byte)(utflen >>> 8 & 0xFF);
      bytearr[(count++)] = (byte)(utflen >>> 0 & 0xFF);
      for (int i = 0; i < strlen; i++) {
        int c = charr[i];
        if ((c >= 1) && (c <= 127)) {
          bytearr[(count++)] = (byte)c;
        }
        else if (c > 2047) {
          bytearr[(count++)] = (byte)(0xE0 | c >> 12 & 0xF);
          bytearr[(count++)] = (byte)(0x80 | c >> 6 & 0x3F);
          bytearr[(count++)] = (byte)(0x80 | c >> 0 & 0x3F);
        }
        else {
          bytearr[(count++)] = (byte)(0xC0 | c >> 6 & 0x1F);
          bytearr[(count++)] = (byte)(0x80 | c >> 0 & 0x3F);
        }
      }
      dataOut.write(bytearr);
    }
    else
    {
      dataOut.writeInt(-1);
    }
  }

  protected void readBody(DataInput dataIn)
    throws IOException
  {
    int utflen = dataIn.readInt();
    if (utflen > -1) {
      StringBuffer str = new StringBuffer(utflen);
      byte[] bytearr = new byte[utflen];

      int count = 0;

      dataIn.readFully(bytearr, 0, utflen);

      while (count < utflen) {
        int c = bytearr[count] & 0xFF;
        switch (c >> 4)
        {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
          count++;
          str.append((char)c);
          break;
        case 12:
        case 13:
          count += 2;
          if (count > utflen) {
            throw new UTFDataFormatException();
          }
          int char2 = bytearr[(count - 1)];
          if ((char2 & 0xC0) != 128) {
            throw new UTFDataFormatException();
          }
          str.append((char)((c & 0x1F) << 6 | char2 & 0x3F));
          break;
        case 14:
          count += 3;
          if (count > utflen) {
            throw new UTFDataFormatException();
          }
          char2 = bytearr[(count - 2)];
          int char3 = bytearr[(count - 1)];
          if (((char2 & 0xC0) != 128) || ((char3 & 0xC0) != 128)) {
            throw new UTFDataFormatException();
          }
          str.append((char)((c & 0xF) << 12 | (char2 & 0x3F) << 6 | (char3 & 0x3F) << 0));
          break;
        case 8:
        case 9:
        case 10:
        case 11:
        default:
          throw new UTFDataFormatException();
        }
      }

      this.text = new String(str);
    }
  }
}